package com.platform.framework.gateway.wxpay;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.annotation.Resource;
import javax.net.ssl.SSLContext;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.Method;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.platform.framework.dao.pub.TradeFlowMybatisDao;
import com.platform.framework.entity.pub.TradeFlow;
import com.platform.framework.entity.wxpay.WxpayReturnInfo;
import com.platform.framework.gateway.wxpay.config.WxpayConfig;
import com.platform.framework.gateway.wxpay.inf.WxpayGateway;
import com.platform.framework.util.net.tool.HttpUtil;
import com.platform.framework.util.pub.JsonUtil;
import com.platform.framework.util.pub.ReflectUtil;
import com.platform.framework.util.pub.Validation;
import com.platform.framework.util.pub.XmlUtil;
import com.platform.framework.util.sign.SignUtil;
import com.platform.framework.vo.pub.ResponseVo;
import com.platform.framework.vo.states.PayGate;
import com.platform.framework.vo.states.PayResult;
import com.platform.framework.vo.transfer.TransportLayer;
import com.tencent.WXPay;
import com.tencent.business.ScanPayBusiness;
import com.tencent.protocol.pay_protocol.ScanPayReqData;
import com.tencent.service.ScanPayService;

/**
 * 微信网关接口实现类
 *
 * @author ly-liuxianliang
 * @version 1.0.0
 * @create time 2016年11月15日
 */
@SuppressWarnings({"unused", "deprecation"})
@Component("WxpayGateway")
public class WxpayGatewayImpl implements WxpayGateway {

    private static Logger logger = Logger.getLogger(WxpayGatewayImpl.class);

    private static ScanPayBusiness scanPayBusiness;

    @Resource
    private TradeFlowMybatisDao tradeFlowMybatisDao;

    @Override
    public String wxpayJsApi(TransportLayer transportLayer) throws Exception {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public String wxpayQRCode(TransportLayer transportLayer) throws Exception {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public WxpayReturnInfo wxpayBarCode(TransportLayer transportLayer) throws Exception {
        // TODO Auto-generated method stub
        WXPay.initSDKConfiguration(
                //签名算法需要用到的秘钥
                transportLayer.getWxKey(),
                //公众账号ID，成功申请公众账号后获得
                transportLayer.getAppid(),
                //商户ID，成功申请微信支付功能之后通过官方发出的邮件获得
                transportLayer.getMchId(),
                //子商户ID，受理模式下必填；
                transportLayer != null ? transportLayer.getSubMchid() : "",
                //HTTP证书在服务器中的路径，用来加载证书用
                "",
                //HTTP证书的密码，默认等于MCHID
                ""
        );
        System.out.println("初始化完成！");
	       /* SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	        Calendar c = Calendar.getInstance();
	        c.setTime(new Date());
	        c.add(Calendar.DAY_OF_MONTH,10);*/
        logger.info("将请求的数据打包!");
        int totalFee = (int) (Double.parseDouble(transportLayer.getTotalAmount()) * 100);
        ScanPayReqData scanPayReqData = new ScanPayReqData(
                transportLayer.getAuthCode(),
                transportLayer.getBody(),
                transportLayer.getAttach(),
                "",
                transportLayer.getOutTradeNo(),
                totalFee,
                "",
                "",
                transportLayer.getSpbillCreateIp(),
                transportLayer.getDetail());
        logger.info("请求数据打包完成，scanPayReqData:" + scanPayReqData.toString());
        String result = new ScanPayService().request(scanPayReqData);
        logger.info("支付结果：" + result);
        WxpayReturnInfo wxpayReturnInfo = new WxpayReturnInfo();
        XmlUtil.xml2Entity(result, wxpayReturnInfo);
        return wxpayReturnInfo;
    }

    @Override
    public WxpayReturnInfo tradeQuery(TransportLayer transportLayer) throws Exception {
        // TODO Auto-generated method stub
        String resultXml = HttpUtil.doHttps("https://api.mch.weixin.qq.com/pay/orderquery", initParams(transportLayer));
        String resultCode = XmlUtil.getParam(resultXml, "result_code");
        String returnCode = XmlUtil.getParam(resultXml, "return_code");
        WxpayReturnInfo wxpayReturnInfo = new WxpayReturnInfo();
        XmlUtil.xml2Entity(resultXml, wxpayReturnInfo);
        return wxpayReturnInfo;
    }

    @Override
    public ResponseVo tradeQueryNoWxService(TransportLayer transportLayer) throws Exception {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public String doRefund(TransportLayer transportLayer) throws Exception {
        // TODO Auto-generated method stub
        String requestXml = initParams(transportLayer);
        return doRefundApply(requestXml, transportLayer);
    }

    @Override
    public String wxReverse(TransportLayer transportLayer) throws Exception {
        // TODO Auto-generated method stub
        String requestXml = initParams(transportLayer);
        return doReverse(requestXml, transportLayer);
    }

    //将参数验签并封装在xml中
    private String initParams(TransportLayer transportLayer) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("appid", transportLayer.getAppid());
        map.put("mch_id", transportLayer.getMchId());
        //map.put("sub_appid", transportLayer.getSubAppid());
        if (!Validation.isEmpty(transportLayer) && !Validation.isEmpty(transportLayer.getSubMchid())) {
            map.put("sub_mch_id", transportLayer.getSubMchid());
        }
        map.put("nonce_str", UUID.randomUUID().toString().replaceAll("-", ""));
        map.put("out_trade_no", transportLayer.getOutTradeNo());
        if (transportLayer.getPayGate().equals(PayGate.WX_H5)) {
            int total_fee = (int) (Double.parseDouble(transportLayer.getTotalAmount()) * 100);
            map.put("total_fee", total_fee);
            map.put("notify_url", WxpayConfig.NOTIFY_URL + "?tradeFlowId=" + transportLayer.getTradeFlowId()); // 将tradeFlowId带上，可以修改订单状态
            map.put("spbill_create_ip", transportLayer.getSpbillCreateIp());
            map.put("body", transportLayer.getBody());
//				map.put("detail", transportLayer.getDetail());
            map.put("trade_type", "JSAPI");
            map.put("openid", transportLayer.getOpenid());
        }

        if (transportLayer.getPayGate().equals(PayGate.QRCODE_PAY)) {
            int total_fee = (int) (Double.parseDouble(transportLayer.getTotalAmount()) * 100);
            map.put("total_fee", total_fee);
            map.put("notify_url", WxpayConfig.NOTIFY_URL);
            map.put("spbill_create_ip", transportLayer.getSpbillCreateIp());
            map.put("body", transportLayer.getBody());
            map.put("trade_type", "NATIVE");
            map.put("product_id", transportLayer.getOutTradeNo());
        }

        if (transportLayer.getPayGate().equals(PayGate.TRADE_REFUND)) {
            map.put("out_refund_no", transportLayer.getOutRefundNo());
            map.put("out_trade_no", transportLayer.getOutTradeNo());
            if (!Validation.isEmpty(transportLayer.getTotalAmount())) {
                int total_fee = (int) (Double.parseDouble(transportLayer.getTotalAmount()) * 100);
                map.put("total_fee", total_fee);
            }
            if (!Validation.isEmpty(transportLayer.getRefundAmount())) {
                int refund_fee = (int) (Double.parseDouble(transportLayer.getRefundAmount()) * 100);
                map.put("refund_fee", refund_fee);
            }
            map.put("op_user_id", transportLayer.getMchId());
        }
        String sign = SignUtil.getSign(map, transportLayer);
        map.put("sign", sign);
        logger.info("[wxpay gateway params]" + map.toString());
        String str = XmlUtil.mapToXml(map);
        return str;
    }

    //撤销
    private static synchronized String doReverse(String xml, TransportLayer transportLayer) throws Exception {
        logger.info("[ClientCustomSSL.doReverse]  request = [" + xml + "] ");
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        FileInputStream instream = new FileInputStream(new File(WxpayConfig.certFilePath));
        try {
            keyStore.load(instream, transportLayer.getMchId().toCharArray());
        } finally {
            instream.close();
        }
        SSLContext sslcontext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, transportLayer.getMchId().toCharArray())
                .build();
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext,
                new String[]{"TLSv1"},
                null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        CloseableHttpClient httpclient = HttpClients.custom()
                .setSSLSocketFactory(sslsf)
                .build();
        String text = "";
        StringBuffer result = new StringBuffer();
        try {
            HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/reverse");
            httppost.setEntity(new StringEntity(xml, WxpayConfig.INPUT_CHARSET));
            logger.info("executing request" + httppost.getRequestLine());
            CloseableHttpResponse response = httpclient.execute(httppost);
            try {
                HttpEntity entity = response.getEntity();
                logger.info(response.getStatusLine());
                if (entity != null) {
                    logger.info("Response content length: " + entity.getContentLength());
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
                    while ((text = bufferedReader.readLine()) != null) {
                        result.append(new String(text.getBytes(), WxpayConfig.INPUT_CHARSET));
                    }
                    logger.info("gateway refund method : text = " + result);
                }
                EntityUtils.consume(entity);
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
        logger.info("[ClientCustomSSL.doReverse]  response = [" + result + "] ");
        return result.toString();
    }

    //退款申请
    private synchronized String doRefundApply(String xml, TransportLayer transportLayer) throws Exception {
        logger.info("[ClientCustomSSL.doRefundApply]  request = [" + xml + "] ");
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        FileInputStream instream = new FileInputStream(new File(WxpayConfig.certFilePath));
        try {
            keyStore.load(instream, transportLayer.getMchId().toCharArray());
        } finally {
            instream.close();
        }
        SSLContext sslcontext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, transportLayer.getMchId().toCharArray())
                .build();
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext,
                new String[]{"TLSv1"},
                null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        CloseableHttpClient httpclient = HttpClients.custom()
                .setSSLSocketFactory(sslsf)
                .build();
        String text = "";
        StringBuffer result = new StringBuffer();
        try {
            HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");
            httppost.setEntity(new StringEntity(xml, WxpayConfig.INPUT_CHARSET));
            logger.info("executing request" + httppost.getRequestLine());
            CloseableHttpResponse response = httpclient.execute(httppost);
            try {
                HttpEntity entity = response.getEntity();
                logger.info(response.getStatusLine());
                if (entity != null) {
                    logger.info("Response content length: " + entity.getContentLength());
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
                    while ((text = bufferedReader.readLine()) != null) {
                        result.append(new String(text.getBytes(), WxpayConfig.INPUT_CHARSET));
                    }
                    logger.info("gateway refund method : text = " + result);
//	                    String resultCode = XmlUtil.getParam(result.toString(), "result_code");
//	                    String errCodeDes = XmlUtil.getParam(result.toString(), "err_code_des");
//	                    String returnCode = XmlUtil.getParam(result.toString(), "return_code");
//	                    String returnMsg = XmlUtil.getParam(result.toString(), "return_msg");
//	                    
//	                    if ("FAIL".equals(returnCode) && Validation.isEmpty(resultCode)) {
//	                    	sendMsgToUser(wxpayReqVo, returnMsg);
//	                    } else if ("FAIL".equals(returnCode) && "FAIL".equals(resultCode) ) {
//	                    	sendMsgToUser(wxpayReqVo, errCodeDes);
//	                    }

                }
                EntityUtils.consume(entity);
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
        logger.info("[ClientCustomSSL.doRefund]  response = [" + result + "] ");
        return result.toString();
    }

    @Override
    public TransportLayer unifiedOrder(TransportLayer transportLayer) throws Exception {
        // TODO Auto-generated method stub
        String apiXmlResult = HttpUtil.doHttps("https://api.mch.weixin.qq.com/pay/unifiedorder", initParams(transportLayer));
//        HttpRequest.post("https://api.mch.weixin.qq.com/pay/unifiedorder").charset("UTF-8").
        String codeUrl = XmlUtil.getParam(apiXmlResult, "code_url");
        String prepayId = XmlUtil.getParam(apiXmlResult, "prepay_id");
        String errCode = XmlUtil.getParam(apiXmlResult, "err_code");
        String resultCode = XmlUtil.getParam(apiXmlResult, "result_code");
        String returnMsg = XmlUtil.getParam(apiXmlResult, "return_msg");
        String outTradeNo = XmlUtil.getParam(apiXmlResult, "out_trade_no");
        String errCodeDes = XmlUtil.getParam(apiXmlResult, "err_code_des");
        TransportLayer transportLayer2 = new TransportLayer();
        transportLayer2.setCodeUrl(codeUrl);
        transportLayer2.setPrepayId(prepayId);
        transportLayer2.setErrCode(errCode);
        transportLayer2.setReturnMsg(returnMsg);
        transportLayer2.setOutTradeNo(outTradeNo);
        transportLayer2.setPrepayId(prepayId);

        logger.info("[wxpay unifiedOrder api result] = " + JsonUtil.Object2Json(transportLayer2));
        return transportLayer2;
    }
}
